package com.abc.util;

import java.io.IOException;
import java.math.BigInteger;

import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;

public class SM2Utils {
    //生成随机秘钥对
    public static void generateKeyPair() {
        SM2 sm2 = SM2.Instance();
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
        BigInteger privateKey = ecpriv.getD();
        ECPoint publicKey = ecpub.getQ();

        System.out.println("公钥: " + Util.byteToHex(publicKey.getEncoded()));
        System.out.println("私钥: " + Util.byteToHex(privateKey.toByteArray()));
    }

    //数据加密
    public static String encrypt(byte[] publicKey, byte[] data) throws IOException {
        if (publicKey == null || publicKey.length == 0) {
            return null;
        }

        if (data == null || data.length == 0) {
            return null;
        }

        byte[] source = new byte[data.length];
        System.arraycopy(data, 0, source, 0, data.length);

        Cipher cipher = new Cipher();
        SM2 sm2 = SM2.Instance();
        ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

        ECPoint c1 = cipher.Init_enc(sm2, userKey);
        cipher.Encrypt(source);
        byte[] c3 = new byte[32];
        cipher.Dofinal(c3);

//		System.out.println("C1 " + Util.byteToHex(c1.getEncoded()));
//		System.out.println("C2 " + Util.byteToHex(source));
//		System.out.println("C3 " + Util.byteToHex(c3));
        //C1 C2 C3拼装成加密字串
        return Util.byteToHex(c1.getEncoded()) + Util.byteToHex(source) + Util.byteToHex(c3);

    }

    //数据解密
    public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException {
        if (privateKey == null || privateKey.length == 0) {
            return null;
        }

        if (encryptedData == null || encryptedData.length == 0) {
            return null;
        }
        //加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2
        String data = Util.byteToHex(encryptedData);
        /***分解加密字串
         * （C1 = C1标志位2位 + C1实体部分128位 = 130）
         * （C3 = C3实体部分64位  = 64）
         * （C2 = encryptedData.length * 2 - C1长度  - C2长度）
         */
        byte[] c1Bytes = Util.hexToByte(data.substring(0, 130));
        int c2Len = encryptedData.length - 97;
        byte[] c2 = Util.hexToByte(data.substring(130, 130 + 2 * c2Len));
        byte[] c3 = Util.hexToByte(data.substring(130 + 2 * c2Len, 194 + 2 * c2Len));

        SM2 sm2 = SM2.Instance();
        BigInteger userD = new BigInteger(1, privateKey);

        //通过C1实体字节来生成ECPoint
        ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
        Cipher cipher = new Cipher();
        cipher.Init_dec(userD, c1);
        cipher.Decrypt(c2);
        cipher.Dofinal(c3);

        //返回解密结果
        return c2;
    }

    public static void main(String[] args) throws Exception {
        //生成密钥对
        //generateKeyPair();

        String plainText = "{\n" +
                "    \"username\":\"罗睿\",\n" +
                "    \"password\":\"123\"\n" +
                "}";
        byte[] sourceData = plainText.getBytes();

        //下面的秘钥可以使用generateKeyPair()生成的秘钥内容
        // 国密规范正式私钥
        String prik = "66138546001C6D771585D6190697DC2876ADB24D8EAEDBDF96339E357CA4C03C";
        // 国密规范正式公钥
        String pubk = "0411346A8BA885E5AB4DE70695A543366565B278F203CB16F8312BC7ECC7FAB6BBE326D22C7A96C7A0B7A0CB18B57F3BD449EAE90BD37CA16DA5BB1299EA8B2432";

        /*System.out.println("加密: ");
        String cipherText = SM2Utils.encrypt(Util.hexToByte(pubk), sourceData);
        System.out.println(cipherText);*/
        System.out.println("解密: ");
        plainText = new String(SM2Utils.decrypt(Util.hexToByte(prik), Util.hexToByte("04BD01072B04B1E77C84241CE22CD1C62FDAF3DE0CBF8CA5AF2E4C3E45F1005181F2382A3F6893DC5625CDD7AB230FBD7079FE9CC1C932C4E44CA9161599832E311745635E78B4FC5DA52CC0C4B592AA41C57AE552655A3B933F3136FE6404D9EB553CCD1FF62AA05554AA17231B9C5CF95CEE43994DEA5A4ACB28F918ED2BBCADF4E2FD68C73D9DDB2D4B55")));
        System.out.println(plainText);
    }
}

//公钥: 0411346A8BA885E5AB4DE70695A543366565B278F203CB16F8312BC7ECC7FAB6BBE326D22C7A96C7A0B7A0CB18B57F3BD449EAE90BD37CA16DA5BB1299EA8B2432
//私钥: 42ACEF5303833A493CABEFDBB4BC30A44048D5D7221DB8091C789B832144620A
//加密: 0419C471EC152DAC3F1E60A2D44F5D213F4BCA03156FDB4F7CCF8AA62A75B07E2933BF9D9522E2BF72A4C3D6B2395657B897B0806BE57C593167019B88036A3C322438337EEFD724252A11B711565EEBD3D0B4508598B04C8EFEE647D91DB044439C58B3CA0202B6FCC1A95C6544EAF1F53DD48464A8FDB607B674D922A8E0915A8924EC5CEF6AB6E3B9F085C2DD1C526CE0
//        解密:
//        {
//        "username":"罗睿",
//        "password":"123"
//        }

//公钥: 045E2EA23F09F2BF8AAFC38B2EC8CBC05631A44555E6A565435C833FF23CA9F5B43B406ABFE0016EF13E8B752E45B4A97A49033018C07ED993A21CB2F8E3187895
//私钥: 66138546001C6D771585D6190697DC2876ADB24D8EAEDBDF96339E357CA4C03C
//加密: 0443804E103A93FD6D3288EFDA007EA70E2C91B66F340C0949844C73741B7B781C8A7BEF38447D5D6581169A0BEBC2E61AE08E94E0BE54BCF6936803C788AE0F1E69F7BFC5D305AD0B314FAC8694D49EED788F8CB7FA4CCE5CF13C1558099A960CC64B8092693A6288FBA61F21667A70A5A48B32409E8FFF724FCCCED7D6617AA692640B464659464938CC5135FD48DE7E6F
//        解密:
//        {
//        "username":"罗睿",
//        "password":"123"
//        }


